/**
 *	---------------------------------------------------------------------------
 *	COMP 6231/FALL 2013
 *	Assignment - 02
 *	@author Talha Rahman (1296884)
 *	---------------------------------------------------------------------------
 *	This class processes each incoming UDP request to the server {@link StationServer}.
 *	This class extends the Thread class and runs concurrently - hence processing each
 *	UDP request in parallel. 
 *	  
 */
package ca.concordia.comp6231.ros.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ca.concordia.comp6231.ros.RequestOrderingService;
import ca.concordia.comp6231.udp.UDPClientThread;

public class UDPServiceRequestProcessorROS extends Thread {

	private RequestOrderingService ros;
	private String responseString;
	private DatagramSocket socket;
	private DatagramPacket request;
	
	String functionName1 = "getRecordCount";
	String functionName2 = "transferRecord";
	String functionName3 = "createCRecord";
	String functionName4 = "createMRecord";
	String functionName5 = "editRecord";
	
	private static long orderNo = 1l;

	public UDPServiceRequestProcessorROS(RequestOrderingService ros, DatagramSocket socket, DatagramPacket request) {
		this.ros = ros;
		this.socket = socket;
		this.request = request;
	}

	@Override
	public void run() {
		String requestStringRaw = new String(request.getData());
		System.out.println("The request string is : " + requestStringRaw);
		
		Map<String, String> params = processRequestString(requestStringRaw);
		String orderedRequestString = "orderNo:" + getNextOrderNo() + "," + requestStringRaw + "";
		
		System.out.println(params);
		
		if (params.get("functionName").equals(functionName1)) {
			responseString = "getRecordCount";
			
			List<UDPClientThread> udpRequestList = new ArrayList<UDPClientThread>();
			UDPClientThread udpRequest1 = sendUDPMessage(orderedRequestString, "localhost", 6780);
			UDPClientThread udpRequest2 = sendUDPMessage(orderedRequestString, "localhost", 6781);
			UDPClientThread udpRequest3 = sendUDPMessage(orderedRequestString, "localhost", 6782);
			
			udpRequestList.add(udpRequest1);
			udpRequestList.add(udpRequest2);
			udpRequestList.add(udpRequest3);

			StringBuilder response = new StringBuilder(); 
			for (UDPClientThread udpRequest : udpRequestList) {
				try {
					udpRequest.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				String udpResponse = udpRequest.getUDPResponseString().trim();
				if (!udpResponse.equals("Invalid Request.")) {
					response.append("," + udpResponse);
				}
			}
			
			responseString = new String(response);
			
			
		} else if(params.get("functionName").equals(functionName2)) {
			responseString = "transferRecord";
		} else if (params.get("functionName").equals(functionName3)) {
			responseString = "createCRecord";
		} else if (params.get("functionName").equals(functionName4)) {
			responseString = "createMRecord";
		} else if (params.get("functionName").equals(functionName5)) {
			responseString = "editRecord";
		} else {
			responseString = "Invalid Request.";
		}

		DatagramPacket reply = new DatagramPacket(responseString.getBytes(),
				responseString.length(), request.getAddress(),
				request.getPort());

		try {
			socket.send(reply);
		} catch (SocketException e) {
			System.out.println("Socket error: " + e.getMessage());
		} catch (IOException e) {
			System.out.println("IO error: " + e.getMessage());
		}
	}
	

	public String getResponseString() {
		return responseString;
	}
	
	public UDPClientThread sendUDPMessage(String message, String hostName, int portNo){
		UDPClientThread udpClientThread = new UDPClientThread(message, hostName, portNo);
		udpClientThread.start();
		
		return udpClientThread;
	}
	
	private Map<String, String> processRequestString(String requestStringRaw) {
		
		String requestString = requestStringRaw.trim();		
		
		List<String> items = Arrays.asList(requestString.trim().split("\\,"));
		Map<String, String> params = new HashMap<String, String>();
		
		for(String item : items) {
			List<String> parts = Arrays.asList(item.trim().split("\\:"));
			String key = parts.get(0);
			String value = parts.get(1);
			params.put(key, value);
		}
		
		return params;
	}
	
	private synchronized long getNextOrderNo() {
		return orderNo++;
	}

}
